package com.mantou.cdl.net;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;

import com.gargoylesoftware.htmlunit.CookieManager;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.mantou.cdl.proxy.ProxyAddress;
import com.mantou.cdl.utils.NullUtil;


public class  HttpInvoker {

	private static final int MAX_VALUE = 10000;
	private String url;
	private int methodType;
	
	private Map<String,String> params;
	
	private static List<ProxyAddress> paList = null;//ProxyIpServiceImpl.getIpList();
	
	private final Random random = new Random();
	
	public  CookieManager cookieManager = new CookieManager();
	
	/**
	 * �?��请求的URL，有可能有重定向。重定向后的url和原来的url就不�?���?
	 */
	private String lastUrl ;
	
	private static final String HTTP_REQUEST_TIMEOUT = "http.request.timeout";
	
	
	public HttpInvoker(String url,int methodType, Map<String,String> params){
		this.url = url;
		this.methodType = methodType;
		this.params = params;
	}

	public HttpResult requestFromHtmlUnit(HtmlUnitResultWait waitHandler){

		WebClient webClient = new WebClient();

		webClient.getOptions().setThrowExceptionOnScriptError(false);  
		webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);   
		webClient.getOptions().setJavaScriptEnabled(true);  
		webClient.getOptions().setActiveXNative(false);  
		webClient.getOptions().setCssEnabled(false);  
		webClient.setAjaxController(new NicelyResynchronizingAjaxController()); 
		
		//cookie
		
		try {
			Set<com.gargoylesoftware.htmlunit.util.Cookie> cookies = cookieManager.getCookies(new URL(url));
			com.gargoylesoftware.htmlunit.CookieManager destCookieManager = webClient.getCookieManager();
			
			Iterator<com.gargoylesoftware.htmlunit.util.Cookie>  it =cookies.iterator();
			while(it.hasNext()){
				com.gargoylesoftware.htmlunit.util.Cookie itemCookie = it.next();
				//itemCookie.
				destCookieManager.addCookie(itemCookie);
			}
			HtmlPage page = webClient
					.getPage(url);
			if(waitHandler != null){
				long timeOut = waitHandler.getTimeOut();
				long interverl = timeOut/100;
				if(interverl <20)
					interverl = 20;
				
				long times =timeOut/interverl;
				if(times < 1)
					times =1;
				
				long testTime =0;
				
				while(testTime<times){
					if(waitHandler.canReturn(page.asXml(), page.getUrl().toString())){
						
						
						Set<com.gargoylesoftware.htmlunit.util.Cookie> fromCookies= webClient.getCookieManager().getCookies();
						Iterator<com.gargoylesoftware.htmlunit.util.Cookie> fromit = fromCookies.iterator();
						
						while(fromit.hasNext()){
							cookieManager.addCookie(fromit.next());
						}
						
						return  new HttpResult(200,null,page.asXml().getBytes());
					}
					testTime ++;
					Thread.sleep(interverl);
				}
			}
			lastUrl =page.getUrl().toString();
			//cookie
			return  new HttpResult(200,null,page.asXml().getBytes());
		} catch (FailingHttpStatusCodeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			webClient.closeAllWindows();
		}

		return new HttpResult(-1,null,null);
	}
	public HttpResult postFromHtmlUnit(HtmlUnitResultWait waitHandler,List<NameValuePair> nvps,String orign,String referer,List<NameValuePair> headers){
		try {
			WebClient webClient = new WebClient();

			webClient.getOptions().setThrowExceptionOnScriptError(false);  
			webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);   
			webClient.getOptions().setJavaScriptEnabled(true);  
			webClient.getOptions().setActiveXNative(false);  
			webClient.getOptions().setCssEnabled(false);  
			webClient.setAjaxController(new NicelyResynchronizingAjaxController()); 
			Set<com.gargoylesoftware.htmlunit.util.Cookie> cookies = cookieManager.getCookies(new URL(url));
			com.gargoylesoftware.htmlunit.CookieManager destCookieManager = webClient.getCookieManager();
			
			Iterator<com.gargoylesoftware.htmlunit.util.Cookie>  it =cookies.iterator();
			while(it.hasNext()){
				com.gargoylesoftware.htmlunit.util.Cookie itemCookie = it.next();
				//itemCookie.
				destCookieManager.addCookie(itemCookie);
			}
			
			
			WebRequest webRequest = new WebRequest(new URL(url), com.gargoylesoftware.htmlunit.HttpMethod.POST);
			if(headers != null){
				for(NameValuePair head:headers){
					webRequest.setAdditionalHeader(head.getName(), head.getValue());
				}
			}
			//((HttpPost)webRequest.getHttpMethod()).
			
			
			webClient.loadWebResponse(webRequest);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	private void setHeader(HttpMethod method,String orign,String referer){
		method.getParams().setParameter(HttpMethodParams.SINGLE_COOKIE_HEADER,true);
		method.addRequestHeader("Connection", "keep-alive");
		method.addRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		method.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36");
		//getMethod.addRequestHeader("Accept-Encoding", "gzip,deflate");
		method.addRequestHeader("Accept-Language", "zh-CN,zh;q=0.8");
		if(!NullUtil.isNull(orign))
			method.addRequestHeader("Origin", orign);
		if(!NullUtil.isNull(referer))
			method.addRequestHeader("Referer", referer);
	}
	
	public HttpResult post(List<NameValuePair> nvps,String orign,String referer,List<NameValuePair> headers){
		try {
			HttpClient httpClient = new HttpClient();
			PostMethod post = new PostMethod(url);
			// set parameters that will be submit

			
			setHeader(post,orign,referer);

			if(headers != null){
				for(NameValuePair nameValuepair:headers){
					post.addRequestHeader(nameValuepair.getName(), nameValuepair.getValue());
				}

			}

			//{retAction, retPassword, retVk,retbackURL,retbackTitle,retSubmit,rettryCount,retmobile,retPasswordValue};
			post.setRequestBody(nvps.toArray(new NameValuePair[nvps.size()]));


			httpClient.getState().addCookies(toHttpClient(cookieManager.getCookies(new URL(url))));
		//	httpClient.getState().addCookies((Cookie[]) cookieManager.getCookies(new URL(url)).toArray());
		//	for(Cookie cookie:cookieManeger.getGookiesArray(new URL(parameters[0]))){
				//cookieManeger.addCookie(cn.richinfo.rwb.Cookie.fromCommHttpClient(cookie));
				//System.out.println("before request "+"   "+cookie.getDomain()+"  "+cookie.getName()+" "+cookie.getPath()+"  "+cookie.getValue()+"  "+cookie.getExpiryDate());
			//}
			
		
			int statusCode = httpClient.executeMethod(post);
			/*
			System.out.println("\r\nrequest:\r\n"+post.getPath());
			Header[] headers= post.getRequestHeaders();
			for(Header header:headers){
				System.out.println(header.getName()+":"+header.getValue());
			}
			
			
			System.out.println("\r\n\r\nresponse:\r\n");
			headers = post.getResponseHeaders();
			for(Header header:headers){
				System.out.println(header.getName()+":"+header.getValue());
			}
			*/
			
			/*
			 * cookie 获取 处理
			 */
			Cookie[] cookies=httpClient.getState().getCookies();
			for(Cookie cookie:cookies){
				cookieManager.addCookie(new com.gargoylesoftware.htmlunit.util.Cookie(cookie.getDomain(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getExpiryDate(), cookie.getSecure(), false));
				//System.out.println("after request "+"   "+cookie.getDomain()+"  "+cookie.getName()+" "+cookie.getPath()+"  "+cookie.getValue()+"  "+cookie.getExpiryDate());
			}
			/*
			System.out.println("\r\nall cookie\r\n");
			Set<cn.richinfo.rwb.Cookie> allcookie = cookieManeger.getCookies();
			Iterator<cn.richinfo.rwb.Cookie> it= allcookie.iterator();
			while(it.hasNext()){
				cn.richinfo.rwb.Cookie item = it.next();
				System.out.println("total cookie:"+item.getDomain() +"  "+item.getName()+"  "+item.getPath()+"  "+item.getValue()+"  "+item.getExpires());
			}
			*/
			if(statusCode == 200){
				return new HttpResult(statusCode,post.getResponseBody());
			}else if(statusCode == 302){
				Header header = post.getResponseHeader("Location");
				String location = null;
				if(header != null){
					location = header.getValue();
				}
				return new HttpResult(statusCode,location,post.getResponseBody());
			}else{
				System.out.println("status Code:"+statusCode);
				return new HttpResult(statusCode);
			}
			
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (HttpException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public HttpResult request() throws HttpException, IOException{
		/* 1.生成 HttpClinet 对象并设置参�?*/
		HttpClient httpClient = new HttpClient();
		httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
		GetMethod getMethod = new GetMethod(url);
		getMethod.setFollowRedirects(false);  
		try{
//			ProxyAddress ipProxy = randomGet();
//			Boolean proxySwitch = Boolean.valueOf((String)SpringPropertyUtil.getProperty(Constants.PROXY_SWITCH));
			//设置代理
//			if(proxySwitch && ipProxy != null && !StringUtils.isBlank(ipProxy.getIp()) 
//					&& !StringUtils.isBlank(String.valueOf(ipProxy.getPort()))){
//				httpClient.getHostConfiguration().setProxy(
//						ipProxy.getIp(),
//						ipProxy.getPort());
//			}
			
			//设置 Http 连接超时 5s
			httpClient.getHttpConnectionManager().getParams()
//							.setConnectionTimeout(getTimeOut());
							.setConnectionTimeout(100000);
			httpClient.getHttpConnectionManager().getParams().setSoTimeout(100000);
			/* 生成 GetMethod 对象并设置参�?*/
			

		//	httpClient.getState().
			
			// 设置 get请求超时
			getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 10000);
			// 设置请求重试处理
			getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
					new DefaultHttpMethodRetryHandler());
			//设置UA
			//getMethod.getParams().setParameter(HttpMethodParams.USER_AGENT,ProxyIpServiceImpl.randomGetUa());
			setHeader(getMethod,null,null);
			
			//Set<cn.richinfo.rwb.Cookie> cookieset = cookieManager.getCookies(new URL(url));
			//Iterator<cn.richinfo.rwb.Cookie> it = cookieset.iterator();
			
			//while(it.hasNext()){
			//	httpClient.getState().addCookies(cn.richinfo.rwb.Cookie.fromHttpClient(cookies));
			//}
			
			
			httpClient.getState().addCookies(toHttpClient(cookieManager.getCookies(new URL(url))));
			//httpClient.getState().addCookies(com.gargoylesoftware.htmlunit.util.Cookie.toHttpClient(cookieManager.getCookies(new URL(""))));
			
			int statusCode = httpClient.executeMethod(getMethod);
			
			/*Header[] headers= getMethod.getRequestHeaders();
			System.out.println("\r\nrequest:\r\n"+getMethod.getPath());
			for(Header header:headers){
				System.out.println(header.getName()+":"+header.getValue());
			}
			
			headers = getMethod.getResponseHeaders();
			System.out.println("\r\nresponse:");
			for(Header header:headers){
				System.out.println(header.getName()+":"+header.getValue());
			}
			*/
			lastUrl = getMethod.getURI().toString();
			
			/*
			 * cookie 获取 处理
			 */
			Cookie[] cookies=httpClient.getState().getCookies();
			for(Cookie cookie:cookies){
				cookieManager.addCookie(new com.gargoylesoftware.htmlunit.util.Cookie(cookie.getDomain(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getExpiryDate(), cookie.getSecure(), false));
				//System.out.println("after request "+"   "+cookie.getDomain()+"  "+cookie.getName()+" "+cookie.getPath()+"  "+cookie.getValue()+"  "+cookie.getExpiryDate());
			}
			/*System.out.println("all cookie");
			Set<cn.richinfo.rwb.Cookie> allcookie = cookieManager.getCookies();
			Iterator<cn.richinfo.rwb.Cookie> it= allcookie.iterator();
			while(it.hasNext()){
				cn.richinfo.rwb.Cookie item = it.next();
				System.out.println("total cookie:"+item.getDomain() +"  "+item.getName()+"  "+item.getPath()+"  "+item.getValue()+"  "+item.getExpires());
			}
			*/
			if(statusCode == 200){
				return new HttpResult(statusCode,getMethod.getResponseBody());
			}else if(statusCode == 302){
				Header header = getMethod.getResponseHeader("Location");
				String location = null;
				if(header != null){
					location = header.getValue();
				}
				return new HttpResult(statusCode,location,getMethod.getResponseBody());
			}else{
				System.out.println("status Code:"+statusCode);
				return new HttpResult(statusCode);
			}
		}finally{
			getMethod.releaseConnection();
		}
		
	}
	
	private ProxyAddress randomGet(){
		if(paList == null || paList.size() == 0){
			return null;
		}
		int size = paList.size();
		int i  = random.nextInt(MAX_VALUE) % size;
		
		return paList.get(i);
	}
	
	private static int getTimeOut(){
		return (StringUtils.isBlank(getRequestTimeOut())?5000:Integer.valueOf(getRequestTimeOut()));
	}
	
	/**
	 * 取得设置的超时时�?
	 * @return
	 */
	private static String getRequestTimeOut() {
		return null;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getLastUrl() {
		return lastUrl;
	}

	public void setLastUrl(String lastUrl) {
		this.lastUrl = lastUrl;
	}
    /**
     * Converts this cookie to an HttpClient cookie.
     * @return an HttpClient version of this cookie
     */
    public static org.apache.commons.httpclient.Cookie toHttpClient(com.gargoylesoftware.htmlunit.util.Cookie inCookie) {
        final org.apache.commons.httpclient.Cookie cookie =
            new org.apache.commons.httpclient.Cookie(inCookie.getDomain(),inCookie.getName(),inCookie.getValue(),inCookie.getPath(),inCookie.getExpires(),inCookie.isSecure());
        return cookie;
    }
    
    /**
     * Converts the specified collection of cookies into an array of HttpClient cookies.
     * @param cookies the cookies to be converted
     * @return the specified cookies, as HttpClient cookies
     */
    public static org.apache.commons.httpclient.Cookie[] toHttpClient(final Collection<com.gargoylesoftware.htmlunit.util.Cookie> cookies) {
        final org.apache.commons.httpclient.Cookie[] array = new org.apache.commons.httpclient.Cookie[cookies.size()];
        final Iterator<com.gargoylesoftware.htmlunit.util.Cookie> it = cookies.iterator();
        for (int i = 0; i < cookies.size(); i++) {
            array[i] = toHttpClient(it.next());
        }
        return array;
    }
}
